/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <Winsock2.h>
#include <ws2tcpip.h>

#include "PacketBuilder.h"
#include "PacketBuilderDhcp.h"

#include "MimicInfoPack.h"

class PacketBuilderEx : public PacketBuilder
{
private:
	PacketBuilderDhcp packetBuilderDhcp;
	MimicInfoPack mimicInfoPack;

	///< Creates SYN packet options according to the OS that I try to mimic
	int BuildSynOptions(BYTE*);

	///< Build the content of an ICMP Echo packet's data according to the OS that I try to mimic
	int BuildIcmpEchoDataBuffer(BYTE*);

	///< Converts an IPv4 address to the format used in DNS requests
	bool AddrToDnsReqAddr(BYTE*, DWORD);
	///< Converts an IPv6 address to the format used in DNS requests
	bool AddrToDnsReqAddr6(BYTE*, in_addr6*);
		char LastSignifiantDigitToHexChar(BYTE);

	///< Converts a name to a DNS request name
	bool NameToDnsReqName(BYTE*, DWORD, BYTE*, DWORD);

	MimicInfo mimicInfo;	///< used across the class to get data

public:
	PacketBuilderEx(void);
	~PacketBuilderEx(void);

	void SetMimic(MimicOS);

	bool BuildPackTcpSyn(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD wDP,					// destination port
			DWORD dwSeq					// sequence
		);

	bool BuildPackTcpSynWithSrcPort(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD wSP, WORD wDP,			// source and destination port
			DWORD dwSeq					// sequence
		);

	bool BuildPackTcpFlat(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD  wDP,					// destination port
			DWORD dwSeq,				// TCP sequence
			DWORD dwAck,				// TCP acknowledge
			BYTE  bFlags				// TCP flags
		);

	bool BuildPackTcpFlatWithSrcPort(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD  wSP,					// source port
			WORD  wDP,					// destination port
			DWORD dwSeq,				// TCP sequence
			DWORD dwAck,				// TCP acknowledge
			BYTE  bFlags				// TCP flags
		);

	bool BuildPackIcmpEchoRequest(
			DWORD dwSA, DWORD dwDA		// source and destination address
		);

	bool BuildPackIcmpEchoRequestWithId(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD wIcmpId				// ICMP ID
		);

	bool BuildPackIcmpEchoRequestWithUserData(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			BYTE* dataIn,				// payload
			int sizeIn					// payload's size
		);

	bool BuildPackEmptyIpProto(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			BYTE bProtocol				// protocol
		);

	bool BuildPackUDPFlat(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD wDstPort				// destination port
		);

	bool BuildPackUDPWithUserData(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD wDstPort,				// destination port
			BYTE* dataIn,				// payload
			int sizeIn					// payload's size
		);

	bool BuildPackUDPWithUserDataAndPort(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			WORD wSrcPort,				// source port
			WORD wDstPort,				// destination port
			BYTE* dataIn,				// payload
			int sizeIn					// payload's size
		);

	bool BuildPackDNSQueryRRPTR(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			DWORD rrAddr				// request address
		);

	bool BuildPackDNSQueryRRPTR6(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			in_addr6* rrAddr			// request address
		);

	bool BuildPackDNSQueryMX(
			DWORD dwSA, DWORD dwDA,		// source and destination address
			BYTE* rrAddr,				// request address
			DWORD rrAddrLen				// request address length
		);

	bool BuildPacketArpRequest(
			BYTE srcMacIn[6],
			BYTE srcIpIn[4],
			BYTE dstIpIn[4]
		);

	bool BuildPacketArpReply(
			BYTE srcMacIn[6],
			BYTE srcIpIn[4],
			BYTE dstMacIn[6],
			BYTE dstIpIn[4]
		);

	bool BuildPacketArpGratuitous
		(
			BYTE srcMacIn[6],
			BYTE srcIpIn[4]
		);

	bool BuildPacketArpRequestDotQ(
			BYTE srcMacIn[6],
			BYTE srcIpIn[4],
			BYTE dstIpIn[4],
			BYTE priorityIn,
			WORD vlanIdIn
		);

	bool BuildPackWolUdp(
			BYTE srcMacIn[6],
			BYTE dstMacIn[6],			// broadcast (FF:FF:FF:FF:FF:FF) or specified ?
			DWORD dwSA,					// source address
			DWORD dwDA,					// destination address (nu cred ca este relevant)
			WORD wDstPort,				// default port is 7 (Depicus), 9 (NetScanTools) or 40000 (ahh.sourceforge.net/wol)
			BYTE wolMacIn[6]
		);

	bool BuildPackWolIcmp(
			BYTE srcMacIn[6],
			BYTE dstMacIn[6],			// specified
			DWORD dwSA,					// source address
			DWORD dwDA,					// destination address (nu cred ca este relevant)
			BYTE wolMacIn[6]
		);

	bool BuildPacketDHCPDiscover(
			BYTE srcMacIn[6],			// source MAC
			DWORD reqIpIn,
			CString srcNameIn,
			DWORD transactionIdIn
		);

	bool BuildPacketDHCPRequest(
			BYTE srcMacIn[6],			// source MAC
			DWORD srvIpIn,				// DHCP server
			DWORD reqIpIn,				// requested IP address
			CString srcNameIn,			// name this host is identified as
			DWORD transactionIdIn,		// DHCP transaction ID
			DWORD leaseTimeIn			// requested lease time, 8 days if 0
		);

	// TODO maxResponseTime should be from OSMT
	bool BuildPacketIGMPQueryGeneral(
			DWORD dwSA,					///< source address
			BYTE version				///< 1, 2 or 3
		);
	bool BuildPacketIGMPQuerySpecific(
			DWORD dwSA, DWORD dwDA,		///< source and destination address
			BYTE version,				///< 2 or 3; 1 does not know about specific queries
			BYTE groupAddress[4]		///
		);
	BYTE GetIgmpMaxResponseTime(void);
};
